package com.imooc.user.controller;

import com.imooc.api.BaseController;
import com.imooc.api.controller.user.UserControllerApi;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.pojo.AppUser;
import com.imooc.pojo.bo.UpdateUserInfoBO;
import com.imooc.pojo.vo.AppUserVO;
import com.imooc.pojo.vo.UserAccountInfoVO;
import com.imooc.user.service.UserService;
import com.imooc.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 用户信息相关接口
 */
@RestController
public class UserController extends BaseController implements UserControllerApi {

    @Autowired
    private UserService userService;

    /**
     * 获得用户基本信息
     */
    @Override
    public GraceJSONResult getUserInfo(String userId) {
        // 判断参数不能为空
        if (StringUtils.isBlank(userId)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.UN_LOGIN);
        }

        // 根据 userId 查询用户的信息
        AppUser user = this.getUser(userId);

        // 精简用户信息, 不一定是所有的信息都返回
        AppUserVO userVO = new AppUserVO();
        BeanUtils.copyProperties(user, userVO);

        // 查询 redis 中用户的关注数和粉丝数, 放入 userVO 到前端渲染
        userVO.setMyFansCounts(getCountsFromRedis(REDIS_WRITER_FANS_COUNTS + ":" + userId));
        userVO.setMyFollowCounts(getCountsFromRedis(REDIS_MY_FOLLOW_COUNTS + ":" + userId));

        // 返回用户信息
        return GraceJSONResult.ok(userVO);
    }

    /**
     * 修改/完善用户信息
     */
    @Override
    public GraceJSONResult
    updateUserInfo(@Valid UpdateUserInfoBO updateUserInfoBO, BindingResult result) {
        // 判断 BindingResult 中是否保存了错误的验证信息, 如果有则需要返回(校验注解产生的错误会被放在这个对象中)
        if (result.hasErrors()) {
            Map<String, String> map = getErrors(result);
            return GraceJSONResult.errorMap(map);
        }

        // 执行更新操作
        userService.updateUserInfo(updateUserInfoBO);

        // 返回前端信息
        return GraceJSONResult.ok();
    }

    @Override
    public GraceJSONResult getAccountInfo(String userId) {
        // 判断参数不能为空
        if (StringUtils.isBlank(userId)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.UN_LOGIN);
        }
        // 根据userId查询用户的信息
        AppUser user = getUser(userId);
        // 返回用户信息
        UserAccountInfoVO accountInfoVO = new UserAccountInfoVO();
        BeanUtils.copyProperties(user, accountInfoVO);
        return GraceJSONResult.ok(accountInfoVO);
    }


    @Override
    public GraceJSONResult queryByIds(String userIds) {
        if (StringUtils.isBlank(userIds)) {
            return GraceJSONResult.errorCustom(ResponseStatusEnum.USER_NOT_EXIST_ERROR);
        }
        List<AppUserVO> publisherList = new ArrayList<>();
        List<String> userIdList = JsonUtils.jsonToList(userIds, String.class);
        for (String userId : userIdList) {
            // 获得用户基本信息
            AppUserVO userVO = getBasicUserInfo(userId);
            // 添加到publisherList
            publisherList.add(userVO);
        }
        return GraceJSONResult.ok(publisherList);
    }

    /**
     * 获取用户信息
     * <p>
     * fixme: 大流量情况下, 长期数据不更新的查询设计
     * 设计思想: 由于用户信息不怎么会变动, 对于一些千万级别的网站来说,
     * 这类信息不会直接去查询数据库, 那么完全可以依靠 redis(任何缓存都可以), 直接把查询后的数据存入到 redis 中
     * 当用户进行个人信息的修改操作的时候再同步更新数据库和缓存信息
     */
    private AppUser getUser(String userId) {
        // 查询判断 redis 中是否包含用户信息
        String userJson = redis.get(REDIS_USER_INFO + ":" + userId);

        // 如果包含则查询后直接返回, 就不去查询数据库了
        if (StringUtils.isNotBlank(userJson)) {
            return JsonUtils.jsonToPojo(userJson, AppUser.class);
        } else {
            AppUser user = userService.getUser(userId);
            redis.set(REDIS_USER_INFO + ":" + userId, JsonUtils.objectToJson(user));
            return user;
        }
    }

    private AppUserVO getBasicUserInfo(String userId) {
        // 根据userId查询用户的信息
        AppUser user = getUser(userId);
        // 返回用户信息
        AppUserVO userVO = new AppUserVO();
        BeanUtils.copyProperties(user, userVO);
        return userVO;
    }
}
